﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nage.Algorithms.Population;
using Nage.Algorithms.Solution;

namespace Nage.Examples.RastriginIsland.Topologies
{
    public class CircleTopology<TSol> : ITopology<TSol> where TSol : ISolution
    {
        #region Private fields
        private List<TopologyNode<TSol>> _nodeList; 
        #endregion

        #region Constructor
        public CircleTopology()
        {
            _nodeList = new List<TopologyNode<TSol>>();
        }

        public CircleTopology(ITopologyMigrator<TSol> migrator)
            : this()
        {
            Migrator = migrator;
        }
        #endregion

        #region Add
        public void Add(IPopulation<TSol> population)
        {
            TopologyNode<TSol> node = new TopologyNode<TSol>(population);
            if (_nodeList.Count == 0)
            {
                _nodeList.Add(node);
            }
            else
            {
                _nodeList.Last().Neighbours.Clear();
                _nodeList.Last().Neighbours.Add(node);
                node.Neighbours.Add(_nodeList.First());
                _nodeList.Add(node);
            }
        } 
        #endregion

        #region GetNeighbours
        public IEnumerable<IPopulation<TSol>> GetNeighbours(IPopulation<TSol> population)
        {
            foreach (var node in _nodeList)
            {
                if (node.Population == population)
                {
                    return node.Neighbours.Select(x => x.Population);
                }
            }
            return null;
        } 
        #endregion

        #region Type
        public TopologyType Type
        {
            get
            {
                return TopologyType.Circle;
            }
        } 
        #endregion

        #region Migrator
        public ITopologyMigrator<TSol> Migrator { get; set; } 
        #endregion

        #region Migrate
        public void Migrate()
        {
            int amount = _nodeList.Count;
            for (int i = 0; i < amount; i++)
            {
                IPopulation<TSol> from = _nodeList[i].Population;
                IPopulation<TSol> to = _nodeList[(i + 1) % amount].Population;
                Migrator.Migrate(ref from, ref to);
            }
        } 
        #endregion

        #region GetEnumerator
        public IEnumerator<TopologyNode<TSol>> GetEnumerator()
        {
            return _nodeList.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _nodeList.GetEnumerator();
        } 
        #endregion
    }
}
